package http

import (
	"gitee.com/captials-team/ubdframe/src/common/consts"
	"gitee.com/captials-team/ubdframe/src/common/utils"
	"gitee.com/captials-team/ubdframe/src/domain/configstc"
	"gitee.com/captials-team/ubdframe/src/domain/converts"
	"gitee.com/captials-team/ubdframe/src/domain/dto"
	"gitee.com/captials-team/ubdframe/src/domain/dto/reqdata"
	"gitee.com/captials-team/ubdframe/src/domain/dto/respdata"
	"gitee.com/captials-team/ubdframe/src/domain/interfaces"
	mysqlDao "gitee.com/captials-team/ubdframe/src/infrastructure/dao/mysql"
	"gitee.com/captials-team/ubdframe/src/pkg/gin_http"
	"gitee.com/captials-team/ubdframe/src/pkg/i18n"
	"gitee.com/captials-team/ubdframe/src/pkg/jwtauth"
	v1log "gitee.com/captials-team/ubdframe/src/pkg/logs"
	"gitee.com/captials-team/ubdframe/src/pkg/passwd"
	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"go.uber.org/dig"
	"golang.org/x/text/language"
	"net/http"
	"time"
)

type AuthController struct {
	l v1log.ILog

	jwtAuth interfaces.ItfJwtParser
	conf    *configstc.AdminAppConfig

	adminModel interfaces.ItfAdminDao

	*gin_http.I18nController
	passwd.SaltMd5Password

	gin_http.AuthExtendInfoOption
}

func NewAuthController(di *dig.Scope, l v1log.ILog, conf *configstc.AdminAppConfig) *AuthController {
	ctr := &AuthController{
		l:          l,
		adminModel: mysqlDao.NewAdminDao(conf.DBConfig),

		jwtAuth: jwtauth.NewJwtTokenHandler(conf.AuthConfig.SecretKey),
		conf:    conf,

		SaltMd5Password: passwd.SaltMd5Password{Salt: conf.PasswordSalt},
	}

	//i18n
	{
		parser := i18n.NewParser()
		//parser.Bundle().MustParseMessageFileBytes([]byte(I18nEn), language.English.String()+".toml")
		//parser.Bundle().MustParseMessageFileBytes([]byte(I18nZh), language.Chinese.String()+".toml")
		//for name, path := range conf.I18nFiles {
		//	parser.Load(path, name+".toml")
		//	l.Info("load i18n path %s: %s, %s", name, path, parser.Lang(name).ParseMsg("Hello"))
		//}
		parser.SetLanguage(language.Chinese)
		parser.CacheLanguages()
		ctr.I18nController = &gin_http.I18nController{
			Parser: i18n.NewParser(),
		}
	}

	return ctr
}

// AuthLogin 授权登录 godoc
// @Summary      Auth-登录
// @Description  登录
// @Tags         admin.auth
// @Produce      json
// @Param        param    body     reqdata.AuthReq  true  "账户信息"
// @success 200  {object} respdata.ResponseData{data=respdata.AuthResp} "授权成功"
// @success 500 {object} respdata.ResponseData{} "授权失败"
// @Router       /mag/auth/login [post]
// @x-response-apikey-token-set {"tokenKey":"response.data.token","apiKey":"AdminKeyAuth"}
func (ctr *AuthController) AuthLogin(ctx *gin.Context) {
	var req reqdata.AuthReq

	ctx.ShouldBindBodyWith(&req, binding.JSON)
	//ctr.l.Info("req %+v", req)

	if req.Account == "" || req.Password == "" {
		ctr.Response(ctx, respdata.CParamsInvalid)
		return
	}

	//查询表
	data, err := ctr.adminModel.QueryByAccount(req.Account)
	if err != nil {
		ctr.l.Error("query err %s", err)
		ctr.Response(ctx, respdata.CError)
		return
	}
	if data == nil {
		ctr.Response(ctx, respdata.CError.MMsg("PasswordWrong"))
		return
	}
	password, salt, err := ctr.adminModel.QueryPassword(data.Id)
	if err != nil {
		ctr.l.Error("query err %s", err)
		ctr.Response(ctx, respdata.CError)
		return
	}
	if password != passwd.GenSaltPasswordByMd5(req.Password, salt) {
		ctr.Response(ctx, respdata.CError.MMsg("PasswordWrong"))
		return
	}

	//禁用用户
	if data.Status != consts.StatusEnable {
		ctr.Response(ctx, respdata.CError.MMsg("AccountDisable"))
		return
	}

	//有效期
	if data.ExpiredAt > 0 && data.ExpiredAt < time.Now().Unix() {
		ctr.Response(ctx, respdata.CError.MMsg("AccountExpired"))
		return
	}

	if data.LastLogin == nil {
		t := time.Now()
		data.LastLogin = &(t)
	}

	authInfo := converts.AdminConvertAuthInfo(data)

	if ctr.AuthExtendInfoOption.ExtendInfoFunc != nil {
		extends := ctr.AuthExtendInfoOption.ExtendInfoFunc(data.Id)
		authInfo.Extends = utils.MergeMap(authInfo.Extends, extends)
	}

	packet, err := converts.AuthToDataPacket(authInfo, time.Duration(ctr.conf.AuthConfig.AuthExpired)*time.Second, ctr.jwtAuth)
	if err != nil {
		ctr.l.Error("token fail %s", err)
		ctr.Response(ctx, respdata.CSysBusy)
		return
	}

	ctr.loginRecord(ctx, packet.Auth)

	gin_http.SetAuth(ctx, packet)

	ctr.Response(ctx, respdata.CSuccess.MData(utils.CopyTo(&packet, new(respdata.AuthResp))))
}

// AuthLogout godoc
// @Summary      Auth-取消授权
// @Description  取消授权
// @Tags         admin.auth
// @Produce      json
// @Security     AdminKeyAuth
// @success 200  {object} respdata.ResponseData{} "取消成功"
// @success 500 {object} respdata.ResponseData{} "取消失败"
// @Router       /mag/auth/logout [post]
func (ctr *AuthController) AuthLogout(ctx *gin.Context) {
	ctx.JSON(http.StatusOK, respdata.CSuccess)
}

// AuthInfo 登录信息 godoc
// @Summary      Auth-登录信息
// @Description  获取登录信息
// @Tags         admin.auth
// @Security     AdminKeyAuth
// @Produce      json
// @success 200  {object} respdata.ResponseData{data=respdata.AuthResp} "授权成功"
// @Router       /mag/auth/info [post]
func (ctr *AuthController) AuthInfo(ctx *gin.Context) {
	auth := gin_http.GetAuthDataPacket(ctx)

	//ctr.l.Debug("auth %d-%s", auth.Auth.Id, auth.Auth.Nickname)
	auth.Token = ""

	ctr.Response(ctx, respdata.CSuccess.MData(utils.CopyTo(&auth, new(respdata.AuthResp))))
}

// AuthCheck godoc
// @Summary      Auth-登录校验
// @Description  登录校验ok正常返回，不通过返回99
// @Tags         user.auth
// @Security     ApiKeyAuth
// @Produce      json
// @success 200  {object} respdata.ResponseData{} "返回结果"
// @Router       /mag/auth/check [post]
func (ctr *AuthController) AuthCheck(ctx *gin.Context) {
	ctr.Response(ctx, respdata.CSuccess)
}

// AuthFreshToken godoc
// @Summary      Auth-刷新授权
// @Description  刷新授权token
// @Tags         admin.auth
// @Produce      json
// @Security     AdminKeyAuth
// @success 200  {object} respdata.ResponseData{data=respdata.AuthResp} "刷新成功"
// @success 500 {object} respdata.ResponseData{} "刷新失败"
// @Router       /mag/auth/fresh_token [post]
// @x-response-apikey-token-set {"tokenKey":"response.data.token","apiKey":"ApiKeyAuth"}
func (ctr *AuthController) AuthFreshToken(ctx *gin.Context) {
	auth := gin_http.GetAuthDataPacket(ctx)
	ctr.Response(ctx, respdata.CSuccess.MData(utils.CopyTo(&auth, new(respdata.AuthResp))))
}

// loginRecord 登录记录
func (ctr *AuthController) loginRecord(ctx *gin.Context, auth dto.AuthInfo) {

	//登录记录
	go func(p *dto.LoginInfoParam) {
		ctr.adminModel.LoginNote(auth.Id, p)
	}(&dto.LoginInfoParam{
		Time:   time.Now(),
		Ip:     ctx.ClientIP(),
		Device: ctx.Request.Header.Get("User-Agent"),
	})
}
